package com.gavin.model;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.List;

import com.gavin.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ------------------------------
 * 执行事务请求对象
 * ------------------------------
 * @author wdm（l311576@sina.com）  @date 2018年3月20日
 * @version 1.0
 */
public final class Request {
	private final static Logger logger= LoggerFactory.getLogger(Request.class);
	public final static String PRINT_GAVIN_TRANS_LOG="PRINT_GAVIN_TRANS_LOG";
	
	private Model model=new Model();
	
	private Request(){}
	
	final public static Request build(String serviceName, String transName){
		Request request=new Request();
		request.model.setServiceName(serviceName);
		request.model.setTransName(transName);
		request.model.set(PRINT_GAVIN_TRANS_LOG, true);//默认打印事务日志
		return request;
	}
	
	final public static Request build(){
		Request request=new Request();
//		request.model.set(PRINT_GAVIN_TRANS_LOG, true);//默认打印事务日志
		return request;
	}

	public Request from(Model model){
		if(model==null){
			return this;
		}
		this.model.copy(model);
		return this;
	}
	
	public Model model(){
		return this.model;
	}
	
	public Request set(String field, Byte value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, Short value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, Integer value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, String value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, Date value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, Long value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, Float value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, Double value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, Boolean value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, Object value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

	public Request set(String field, Model value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}

    public Request set(String field, Byte[] value) {
        if(value==null){
            return this;
        }
        this.model.set(field, value);
        return this;
    }

    public Request set(String field, Short[] value) {
        if(value==null){
            return this;
        }
        this.model.set(field, value);
        return this;
    }

    public Request set(String field, Integer[] value) {
        if(value==null){
            return this;
        }
        this.model.set(field, value);
        return this;
    }

    public Request set(String field, Long[] value) {
        if(value==null){
            return this;
        }
        this.model.set(field, value);
        return this;
    }

    public Request set(String field, Float[] value) {
        if(value==null){
            return this;
        }
        this.model.set(field, value);
        return this;
    }

    public Request set(String field, Double[] value) {
        if(value==null){
            return this;
        }
        this.model.set(field, value);
        return this;
    }

    public Request set(String field, Boolean[] value) {
        if(value==null){
            return this;
        }
        this.model.set(field, value);
        return this;
    }


//    public Request set(String field, byte[] value) {
//        if(value==null){
//            return this;
//        }
//        this.model.set(field, value);
//        return this;
//    }
//
//    public Request set(String field, short[] value) {
//        if(value==null){
//            return this;
//        }
//        this.model.set(field, value);
//        return this;
//    }
//
//    public Request set(String field, int[] value) {
//        if(value==null){
//            return this;
//        }
//        this.model.set(field, value);
//        return this;
//    }

    public Request set(String field, String[] value) {
        if(value==null){
            return this;
        }
        this.model.set(field, value);
        return this;
    }

//    public Request set(String field, long[] value) {
//        if(value==null){
//            return this;
//        }
//        this.model.set(field, value);
//        return this;
//    }
//
//    public Request set(String field, float[] value) {
//        if(value==null){
//            return this;
//        }
//        this.model.set(field, value);
//        return this;
//    }
//
//    public Request set(String field, double[] value) {
//        if(value==null){
//            return this;
//        }
//        this.model.set(field, value);
//        return this;
//    }
//
//    public Request set(String field, boolean[] value) {
//        if(value==null){
//            return this;
//        }
//        this.model.set(field, value);
//        return this;
//    }

	public Request set(String field, Model[] value) {
		if(value==null){
			return this;
		}
		this.model.set(field, value);
		return this;
	}
	
	public String getString(String field){
		return this.model.getString(field);
	}
	
	public Long getLong(String field){
		return this.model.getLong(field);
	}
	
	public Integer getInteger(String field){
		return this.model.getInteger(field);
	}
	
	public Request currentTime(){
		this.set("currentTime", DateUtils.date2String(new Date()));
		return this;
	}
	
	/**
	 * 忽略日志
	 * @return
	 */
	public Request ignoreLog(){
		if(this.model.exists(PRINT_GAVIN_TRANS_LOG)){
			this.model().remove(PRINT_GAVIN_TRANS_LOG);
		}
		return this;
	}
	
	public String getServiceName(){
		return this.model.getServiceName();
	}
	
	public String getTransName(){
		return this.model.getTransName();
	}
	
	public static void setTotalPage(Model model) {
		Long totalCount=model.getLong("totalCount");
		Long pageSize=model.getLong("pageSize");
		if(totalCount==null || pageSize==null){
			return;
		}
		int totalPage = (int) (totalCount / pageSize);
		if (totalCount % pageSize != 0) {
			totalPage++;
		}
		model.set("totalPage", totalPage);
	}
	
	public Request page(int pageNumber, int pageSize) {
		this.set("pageNumber", pageNumber);
		this.set("pageSize", pageSize);
		return this;
	}

	/**
	 * <pre>
	 * 支持
	 * list集合 默认取值 list[i].属性名
	 * Object[]数组 默认取值 list[i].属性名
	 * Model[]数组 默认取值 list[i].属性名
	 * java bean
	 * 数据映射
	 * @param obj
	 * @return
	 * </pre>
	 */
	public Request from(Object obj) {
		if(obj==null){
			return this;
		}
		if(obj instanceof List){
			return from((List<?>)obj ,"list");
		}else if(obj instanceof Model[]){//Model[]数组 
			this.set("list", (Model[])obj);
			return this;
		}else if(obj instanceof Object[]){
			return from((Object[])obj,"list");
		}
		Field[] fields=obj.getClass().getDeclaredFields();
		Method[] methods=obj.getClass().getMethods();
		for (int i = 0; i < fields.length; i++) {
			fields[i].setAccessible( true ); 
			try {
				if(filter(fields[i])){continue;}

				DataType dataType=DataType.getDataType(fields[i].getType().getSimpleName());
				if(dataType==DataType._obj){
					if(fields[i].get(obj)!=null){
						if(fields[i].get(obj) instanceof Integer){
							this.model.set(fields[i].getName(), Integer.valueOf(fields[i].get(obj)+""));
						}else if(fields[i].get(obj) instanceof String){
							this.model.set(fields[i].getName(), fields[i].get(obj)+"");
						}else if(fields[i].get(obj) instanceof Long){
							this.model.set(fields[i].getName(), Long.valueOf(fields[i].get(obj)+""));
						}else{
							this.model.set(fields[i].getName(), from(new Model(),fields[i].get(obj),INIT_COUNT));
						}
					}
				}else{
					this.model.set(dataType,fields[i].getName(), fields[i].get(obj));
				}
				
			} catch (Exception e) {
				e.printStackTrace();
				System.out.println("Injector error!!!:"+e.getMessage() );
			}
		}
		return this;
	}

	private static boolean filter(Field field){
		boolean isStatic = Modifier.isStatic(field.getModifiers());
		if(isStatic) {
			return isStatic;
		}
		return field.isEnumConstant();
	}

	public Request from(Object obj,String attrName) {
		if(obj instanceof List){
			return from((List<?>)obj , attrName);
		}else if(obj instanceof Model[]){//Model[]数组 
			this.set(attrName, (Model[])obj);
			return this;
		}else if(obj instanceof Object[]){
			return from((Object[])obj , attrName);
		}
		Model model=new Model();
		Field[] fields=obj.getClass().getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			fields[i].setAccessible( true ); 
			try {
				if(filter(fields[i])){continue;}
				DataType dataType=DataType.getDataType(fields[i].getType().getSimpleName());
				if(dataType==DataType._obj){
					if(fields[i].get(obj)!=null){
						if(fields[i].get(obj) instanceof Integer){
							model.set(fields[i].getName(), Integer.valueOf(fields[i].get(obj)+""));
						}else if(fields[i].get(obj) instanceof String){
							model.set(fields[i].getName(), fields[i].get(obj)+"");
						}else if(fields[i].get(obj) instanceof Long){
							model.set(fields[i].getName(), Long.valueOf(fields[i].get(obj)+""));
						}else{
							model.set(fields[i].getName(), from(new Model(),fields[i].get(obj),INIT_COUNT));
						}
					}
				}else{
					model.set(dataType,fields[i].getName(), fields[i].get(obj));
				}
				
			} catch (Exception e) {
				e.printStackTrace();
				System.out.println("Injector error!!!:"+e.getMessage() );
			}
		}
		this.model.set(attrName, model);
		return this;
	}
	
	/**
	 * Object[]数据映射
	 * @param list
	 * @param attrName
	 * @return
	 */
	private Request from(Object[] list,String attrName) {		
		Model[] models=new Model[list.length];
		for (int a = 0; a < list.length; a++) {
			models[a]=new Model();
			Object obj=list[a];
			Field[] fields=obj.getClass().getDeclaredFields();
			for (int i = 0; i < fields.length; i++) {
				fields[i].setAccessible( true ); 
				try {
					if(filter(fields[i])){continue;}
					DataType dataType=DataType.getDataType(fields[i].getType().getSimpleName());
					if(dataType==DataType._obj){
						if(fields[i].get(obj)!=null){
							if(fields[i].get(obj) instanceof Integer){
								models[a].set(fields[i].getName(), Integer.valueOf(fields[i].get(obj)+""));
							}else if(fields[i].get(obj) instanceof String){
								models[a].set(fields[i].getName(), fields[i].get(obj)+"");
							}else if(fields[i].get(obj) instanceof Long){
								models[a].set(fields[i].getName(), Long.valueOf(fields[i].get(obj)+""));
							}else{
								models[a].set(fields[i].getName(), from(new Model(),fields[i].get(obj),INIT_COUNT));
							}
						}
					}else{
						models[a].set(dataType,fields[i].getName(), fields[i].get(obj));
					}
				} catch (Exception e) {
					e.printStackTrace();
					System.out.println("Injector error!!!:"+e.getMessage() );
				}
			}
		}
		this.model.set(attrName,models);
		return this;
	}	
	
	/**
	 * list数据映射
	 * @param list
	 * @param name
	 * @return
	 */
	public Request from(List<?> list,String name) {
		Model[] models=new Model[list.size()];
		for (int a = 0; a < list.size(); a++) {
			models[a]=new Model();
			Object obj=list.get(a);
			if(obj instanceof Model){
				models[a]=(Model)obj;
				continue;
			}
			Field[] fields=obj.getClass().getDeclaredFields();
			for (int i = 0; i < fields.length; i++) {
				fields[i].setAccessible( true ); 
				try {
					if(filter(fields[i])){continue;}
					DataType dataType=DataType.getDataType(fields[i].getType().getSimpleName());
					if(dataType==DataType._obj){
						if(obj.getClass().getCanonicalName().contains(fields[i].get(obj).getClass().getCanonicalName()+".")){//过滤，否则会导致递归反射内存溢出
							continue;
						}
						
						if(fields[i].get(obj)!=null){
							if(fields[i].get(obj) instanceof Integer){
								models[a].set(fields[i].getName(), Integer.valueOf(fields[i].get(obj)+""));
							}else if(fields[i].get(obj) instanceof String){
								models[a].set(fields[i].getName(), fields[i].get(obj)+"");
							}else if(fields[i].get(obj) instanceof Long){
								models[a].set(fields[i].getName(), Long.valueOf(fields[i].get(obj)+""));
							}else{
								models[a].set(fields[i].getName(), from(new Model(),fields[i].get(obj),INIT_COUNT));
							}
						}
					}else{
						models[a].set(dataType,fields[i].getName(), fields[i].get(obj));
					}
				} catch (Exception e) {
					e.printStackTrace();
					System.out.println("Injector error!!!:"+e.getMessage() );
				}
			}
		}
		this.model.set(name,models);
		return this;
	}

	public static final int totalCount=3;//超过x次忽略
	public static final int INIT_COUNT=1;
	private Model from(Model model,Object obj,int count) {
		if(count>totalCount){
			logger.warn("bean is too many force-completed...");
			return model;
		}

		Field[] fields=obj.getClass().getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			fields[i].setAccessible( true );
			try {
				if(filter(fields[i])){continue;}
				DataType dataType=DataType.getDataType(fields[i].getType().getSimpleName());
				if(dataType==DataType._obj){
					if(fields[i].get(obj)!=null){
						count++;
						model.set(fields[i].getName(), from(new Model(),fields[i].get(obj),count));
					}
				}else{
					model.set(dataType,fields[i].getName(), fields[i].get(obj));
				}
				
			} catch (Exception e) {
				e.printStackTrace();
				System.out.println("Injector error!!!:"+e.getMessage() );
			}
		}
		return model;
	}	
		
	public static String arr2json(Model[] model){
		StringBuffer sb=new StringBuffer("[");
		for (int i = 0; i < model.length; i++) {
			sb.append(model[i].toJson());
			if(i+1<model.length){
				sb.append(",");
			}
		}
		sb.append("]");
		return sb.toString();
	}
//	public static void main(String[] args) {
//		com.gavin.test.bean.Data data=new com.gavin.test.bean.Data();
//		data.setB((byte)1);
//		data.setBn(true);
//		data.setD(1d);
//		data.setF(1f);
//		data.setI(2);
//		data.setL(8l);
//		data.setS("string");
//		data.setSt((short)2);
//		boolean[] dd={true,false};
//		data.setBns(dd);
//		Request.build().from(data);
//		String type=null;
//		Request request=Request.build("","").set("dsad", type).from(data);
//		System.out.println(request.model);
//	}
	
}
